"""
配置热重载器
提供配置的热重载和服务重启功能
"""

import asyncio
import logging
import signal
import os
import sys
from typing import Dict, Any, List, Callable
from datetime import datetime
from .notifier import ConfigNotifier


class ConfigReloader:
    """配置重载器"""

    def __init__(self, config_manager):
        self.config_manager = config_manager
        self.logger = logging.getLogger(__name__)
        self._reload_callbacks: Dict[str, List[Callable]] = {}
        self._is_reloading = False
        self._last_reload_time = None

    async def reload_config(self, key: str = None, changed_by: str = "system") -> bool:
        """
        热重载配置

        Args:
            key: 配置键名，None表示重载所有配置
            changed_by: 操作人

        Returns:
            bool: 重载是否成功
        """
        if self._is_reloading:
            self.logger.warning("Config reload is already in progress")
            return False

        self._is_reloading = True
        reload_start_time = datetime.now()

        try:
            self.logger.info(f"Starting config reload: {key or 'ALL'} by {changed_by}")

            # 1. 从数据库重新加载配置
            if key:
                success = await self._reload_single_config(key)
            else:
                success = await self._reload_all_configs()

            if not success:
                self.logger.error("Config reload failed")
                return False

            # 2. 执行重载回调
            await self._execute_reload_callbacks(key)

            # 3. 通知订阅者
            if hasattr(self.config_manager, '_subscribers'):
                for subscriber in self.config_manager._subscribers:
                    try:
                        await subscriber.on_config_reloaded(key)
                    except Exception as e:
                        self.logger.error(f"Error notifying subscriber {type(subscriber).__name__}: {e}")

            self._last_reload_time = reload_start_time
            reload_duration = (datetime.now() - reload_start_time).total_seconds()

            self.logger.info(f"Config reload completed successfully in {reload_duration:.2f}s: {key or 'ALL'}")
            return True

        except Exception as e:
            self.logger.error(f"Config reload failed with error: {e}")
            return False
        finally:
            self._is_reloading = False

    async def _reload_single_config(self, key: str) -> bool:
        """重载单个配置"""
        try:
            # 从数据库获取最新配置
            item = await self.config_manager._repository.get_config_item_by_key(key)
            if not item:
                self.logger.error(f"Config item not found: {key}")
                return False

            # 更新缓存
            current_value = item['current_value'] or item['default_value']
            if current_value is not None:
                parsed_value = self.config_manager._parse_config_value(current_value, item['data_type'])
                async with self.config_manager._lock:
                    self.config_manager._config_cache[key] = parsed_value

            self.logger.info(f"Reloaded single config: {key}")
            return True

        except Exception as e:
            self.logger.error(f"Failed to reload config {key}: {e}")
            return False

    async def _reload_all_configs(self) -> bool:
        """重载所有配置"""
        return await self.config_manager.load_all_configs()

    def register_reload_callback(self, category: str, callback: Callable):
        """
        注册重载回调函数

        Args:
            category: 配置类别或配置键名
            callback: 回调函数
        """
        if category not in self._reload_callbacks:
            self._reload_callbacks[category] = []
        self._reload_callbacks[category].append(callback)
        self.logger.info(f"Registered reload callback for category: {category}")

    def unregister_reload_callback(self, category: str, callback: Callable = None):
        """
        取消注册重载回调函数

        Args:
            category: 配置类别或配置键名
            callback: 回调函数，None表示移除该类别的所有回调
        """
        if category in self._reload_callbacks:
            if callback is None:
                del self._reload_callbacks[category]
                self.logger.info(f"Removed all reload callbacks for category: {category}")
            else:
                try:
                    self._reload_callbacks[category].remove(callback)
                    self.logger.info(f"Removed specific reload callback for category: {category}")
                except ValueError:
                    pass

    async def _execute_reload_callbacks(self, key: str = None):
        """执行重载回调"""
        callbacks_to_execute = []

        # 收集需要执行的回调
        for category, callbacks in self._reload_callbacks.items():
            if key is None:
                # 重载所有配置，执行所有回调
                callbacks_to_execute.extend(callbacks)
            elif category == key:
                # 重载特定配置，执行匹配的回调
                callbacks_to_execute.extend(callbacks)
            elif self._category_matches_config(category, key):
                # 配置类别匹配
                callbacks_to_execute.extend(callbacks)

        # 执行回调
        for callback in callbacks_to_execute:
            try:
                if asyncio.iscoroutinefunction(callback):
                    await callback(key)
                else:
                    callback(key)
            except Exception as e:
                self.logger.error(f"Error executing reload callback: {e}")

    def _category_matches_config(self, category: str, config_key: str) -> bool:
        """检查配置类别是否匹配配置键"""
        # 简单的匹配规则，可以根据需要扩展
        category_patterns = {
            'model': ['LLM_', 'ASR_', 'TTS_', 'RERANK_', 'EMBEDDING_'],
            'database': ['MYSQL_', 'DB_', 'SQL_'],
            'tools': ['TOOLS_', 'NL2SQL_', 'ADB_', 'TIME_'],
            'digital_human': ['ANY4DH_', 'VOICE_'],
            'external': ['DINGTALK_', 'WEB_SEARCH_']
        }

        if category in category_patterns:
            patterns = category_patterns[category]
            return any(config_key.startswith(pattern) for pattern in patterns)

        return category == config_key


class ServiceRestarter:
    """服务重启器"""

    def __init__(self, config_manager):
        self.config_manager = config_manager
        self.logger = logging.getLogger(__name__)
        self._is_restarting = False
        self._restart_callbacks: List[Callable] = []
        self._last_restart_time = None

    async def restart_service(self, reason: str = "Manual restart", changed_by: str = "admin") -> bool:
        """
        重启服务

        Args:
            reason: 重启原因
            changed_by: 操作人

        Returns:
            bool: 重启是否成功
        """
        if self._is_restarting:
            self.logger.warning("Service restart is already in progress")
            return False

        self._is_restarting = True
        restart_start_time = datetime.now()

        try:
            self.logger.info(f"Starting service restart: {reason} by {changed_by}")

            # 1. 记录重启操作
            await self.config_manager._history_manager.record_service_restart(
                changed_by=changed_by,
                reason=reason
            )

            # 2. 执行重启前回调
            await self._execute_pre_restart_callbacks()

            # 3. 通知订阅者
            if hasattr(self.config_manager, '_subscribers'):
                for subscriber in self.config_manager._subscribers:
                    try:
                        await subscriber.on_service_restart()
                    except Exception as e:
                        self.logger.error(f"Error notifying subscriber {type(subscriber).__name__}: {e}")

            # 4. 创建重启前的快照
            await self._create_pre_restart_snapshot()

            # 5. 执行实际的重启操作
            await self._perform_restart(reason)

            self._last_restart_time = restart_start_time
            restart_duration = (datetime.now() - restart_start_time).total_seconds()

            self.logger.info(f"Service restart completed successfully in {restart_duration:.2f}s")
            return True

        except Exception as e:
            self.logger.error(f"Service restart failed: {e}")
            return False
        finally:
            self._is_restarting = False

    async def _execute_pre_restart_callbacks(self):
        """执行重启前回调"""
        for callback in self._restart_callbacks:
            try:
                if asyncio.iscoroutinefunction(callback):
                    await callback()
                else:
                    callback()
            except Exception as e:
                self.logger.error(f"Error executing pre-restart callback: {e}")

    async def _create_pre_restart_snapshot(self):
        """创建重启前快照"""
        try:
            configs = await self.config_manager.get_all_configs()
            await self.config_manager._backup_manager.create_auto_backup(
                configs, "Pre-restart snapshot"
            )
        except Exception as e:
            self.logger.error(f"Failed to create pre-restart snapshot: {e}")

    async def _perform_restart(self, reason: str):
        """执行实际的重启操作"""
        # 获取当前进程ID
        current_pid = os.getpid()

        # 根据不同的重启策略执行重启
        restart_method = os.getenv('RESTART_METHOD', 'signal')

        if restart_method == 'signal':
            await self._restart_with_signal(current_pid, reason)
        elif restart_method == 'script':
            await self._restart_with_script(reason)
        elif restart_method == 'docker':
            await self._restart_with_docker(reason)
        else:
            self.logger.warning(f"Unknown restart method: {restart_method}")

    async def _restart_with_signal(self, pid: int, reason: str):
        """使用信号重启"""
        try:
            # 在Windows上，信号处理有限制
            if sys.platform == 'win32':
                self.logger.info("Windows platform detected, using alternative restart method")
                # Windows下可以使用其他方法，比如重新启动进程
                await self._restart_windows_process(reason)
            else:
                # Unix-like系统，使用SIGTERM信号
                os.kill(pid, signal.SIGTERM)
                self.logger.info(f"Sent SIGTERM signal to process {pid}")

        except Exception as e:
            self.logger.error(f"Failed to restart with signal: {e}")
            raise

    async def _restart_windows_process(self, reason: str):
        """Windows下的重启方法"""
        try:
            # 方法1: 使用系统命令重启
            import subprocess
            current_script = sys.argv[0]

            # 启动新的进程
            subprocess.Popen([sys.executable, current_script] + sys.argv[1:])

            # 给新进程一些启动时间
            await asyncio.sleep(2)

            # 退出当前进程
            self.logger.info("Windows restart: New process started, exiting current process")
            os._exit(0)

        except Exception as e:
            self.logger.error(f"Failed to restart Windows process: {e}")
            raise

    async def _restart_with_script(self, reason: str):
        """使用脚本重启"""
        restart_script = os.getenv('RESTART_SCRIPT')
        if not restart_script:
            self.logger.warning("RESTART_SCRIPT not set, falling back to signal restart")
            await self._restart_with_signal(os.getpid(), reason)
            return

        try:
            import subprocess
            result = subprocess.run([restart_script, reason], capture_output=True, text=True)
            if result.returncode != 0:
                self.logger.error(f"Restart script failed: {result.stderr}")
            else:
                self.logger.info("Restart script executed successfully")
        except Exception as e:
            self.logger.error(f"Failed to restart with script: {e}")
            raise

    async def _restart_with_docker(self, reason: str):
        """Docker环境重启"""
        container_name = os.getenv('DOCKER_CONTAINER_NAME')
        if not container_name:
            self.logger.warning("DOCKER_CONTAINER_NAME not set, falling back to signal restart")
            await self._restart_with_signal(os.getpid(), reason)
            return

        try:
            import subprocess
            # 重启Docker容器
            subprocess.run(['docker', 'restart', container_name], check=True)
            self.logger.info(f"Docker container {container_name} restarted")
        except Exception as e:
            self.logger.error(f"Failed to restart Docker container: {e}")
            raise

    def register_restart_callback(self, callback: Callable):
        """注册重启回调函数"""
        self._restart_callbacks.append(callback)
        self.logger.info("Registered service restart callback")

    def unregister_restart_callback(self, callback: Callable):
        """取消注册重启回调函数"""
        try:
            self._restart_callbacks.remove(callback)
            self.logger.info("Unregistered service restart callback")
        except ValueError:
            pass


class GracefulShutdownHandler:
    """优雅关闭处理器"""

    def __init__(self, config_manager):
        self.config_manager = config_manager
        self.logger = logging.getLogger(__name__)
        self._shutdown_callbacks: List[Callable] = []
        self._is_shutting_down = False

    async def graceful_shutdown(self, signum=None, frame=None):
        """优雅关闭"""
        if self._is_shutting_down:
            self.logger.info("Shutdown is already in progress")
            return

        self._is_shutting_down = True
        shutdown_start_time = datetime.now()

        self.logger.info("Starting graceful shutdown...")

        try:
            # 1. 执行关闭回调
            await self._execute_shutdown_callbacks()

            # 2. 保存当前状态
            await self._save_current_state()

            # 3. 关闭数据库连接
            if hasattr(self.config_manager, '_db_manager'):
                await self.config_manager._db_manager.close()

            shutdown_duration = (datetime.now() - shutdown_start_time).total_seconds()
            self.logger.info(f"Graceful shutdown completed in {shutdown_duration:.2f}s")

        except Exception as e:
            self.logger.error(f"Error during graceful shutdown: {e}")
        finally:
            # 退出程序
            os._exit(0)

    async def _execute_shutdown_callbacks(self):
        """执行关闭回调"""
        for callback in self._shutdown_callbacks:
            try:
                if asyncio.iscoroutinefunction(callback):
                    await callback()
                else:
                    callback()
            except Exception as e:
                self.logger.error(f"Error executing shutdown callback: {e}")

    async def _save_current_state(self):
        """保存当前状态"""
        try:
            # 保存当前配置快照
            configs = await self.config_manager.get_all_configs()
            await self.config_manager._backup_manager.create_auto_backup(
                configs, "Pre-shutdown snapshot"
            )
        except Exception as e:
            self.logger.error(f"Failed to save current state: {e}")

    def register_shutdown_callback(self, callback: Callable):
        """注册关闭回调函数"""
        self._shutdown_callbacks.append(callback)
        self.logger.info("Registered shutdown callback")

    def unregister_shutdown_callback(self, callback: Callable):
        """取消注册关闭回调函数"""
        try:
            self._shutdown_callbacks.remove(callback)
            self.logger.info("Unregistered shutdown callback")
        except ValueError:
            pass

    def setup_signal_handlers(self):
        """设置信号处理器"""
        if sys.platform != 'win32':
            # Unix-like系统
            signal.signal(signal.SIGTERM, lambda s, f: asyncio.create_task(self.graceful_shutdown(s, f)))
            signal.signal(signal.SIGINT, lambda s, f: asyncio.create_task(self.graceful_shutdown(s, f)))
        else:
            # Windows系统
            signal.signal(signal.SIGINT, lambda s, f: asyncio.create_task(self.graceful_shutdown(s, f)))


# 集成到ConfigManager中的扩展功能
class ConfigManagerExtensions:
    """配置管理器扩展功能"""

    @staticmethod
    def setup_reload_and_restart(config_manager):
        """为配置管理器设置重载和重启功能"""

        # 创建重载器和重启器
        config_manager._reloader = ConfigReloader(config_manager)
        config_manager._restarter = ServiceRestarter(config_manager)
        config_manager._shutdown_handler = GracefulShutdownHandler(config_manager)

        # 扩展配置管理器的方法
        async def extended_reload_config(key=None, changed_by="system"):
            return await config_manager._reloader.reload_config(key, changed_by)

        async def extended_restart_service(reason="Manual restart", changed_by="admin"):
            return await config_manager._restarter.restart_service(reason, changed_by)

        async def extended_graceful_shutdown():
            return await config_manager._shutdown_handler.graceful_shutdown()

        # 添加扩展方法
        config_manager.reload_config = extended_reload_config
        config_manager.restart_service = extended_restart_service
        config_manager.graceful_shutdown = extended_graceful_shutdown

        # 设置信号处理器
        config_manager._shutdown_handler.setup_signal_handlers()

        return config_manager